#pragma once
#include"index.hpp"
#include"util.hpp"
#include<fstream>
#include<jsoncpp/json/json.h>
#include<unordered_map>
#include<algorithm>

namespace ns_searcher
{

    struct InvertedElemPrint
    {
        uint64_t doc_id;
        int weight;
        std::vector<std::string> words;
        InvertedElemPrint():doc_id(0),weight()
        {}
    };


    class Searcher
    {
    public:
        Searcher()
        {}
        ~Searcher()
        {}

        void InitSearcher(const std::string& input)
        {
            //1获取或者创建index对象
            index=ns_index::Index::GetInstance();
            //std::cout<<"获取index单例成功..."<<std::endl;            
            LOG(NORMAL,"获取index单例成功...");
            //2.根据index对象创立索引
            index->BuildIndex(input);
            //std::cout<<"建立正排倒排索引成功"<<std::endl;
            LOG(NORMAL,"建立正排倒排索引成功");
        }

        //query:搜索关键字
        //json_string:返回给用户浏览器的搜索结果
        void Search(const std::string& query,std::string* json_string)
        {
            //1.[分词]对我们的query进行searcher的要求进行分词
            std::vector<std::string> results;
            ns_util::JiebaUtil::CutString(query,&results);

            //2.[触发]:就是根据分词的各个词，进行index查找。


            std::vector<InvertedElemPrint> inverted_list_all;

            std::unordered_map<uint64_t,InvertedElemPrint> tokens_map;

         //   ns_index::InvertedList inverted_list_all;
            for(auto x:results)
            {
                

                boost::to_lower(x);        
                ns_index::InvertedList* inverted_list=index->GetInvertedList(x);
                if(inverted_list==nullptr)
                {
                    continue;
                }
                //这里可能存在重复InvertElem，暂时先放在这里
                //inverted_list_all.insert(inverted_list_all.end(),inverted_list->begin(),inverted_list->end());
                
                for(const auto& elem:*inverted_list)
                {
                    auto& item=tokens_map[elem.doc_id];
                    item.doc_id=elem.doc_id;
                    item.weight+=elem.weight;
                    item.words.push_back(elem.word);
                }
            }

            for(const auto& x:tokens_map)
            {
                inverted_list_all.push_back(x.second);
            }
            
            //3.[合并排序]:汇总查找结果，按照相关性(weight)降序排序
            std::sort(inverted_list_all.begin(),inverted_list_all.end(),[](const InvertedElemPrint &e1,const InvertedElemPrint &e2){
                    return e1.weight>e2.weight;
                    });
            
            //4.[构建]:根据查找的结果，构建json串--jsoncpp
            Json::Value root;
            for(auto& x:inverted_list_all)
            {
                ns_index::DocInfo* doc=index->GetForwardIndex(x.doc_id);
                if(doc==nullptr)
                {
                    continue;
                }

                Json::Value elem;
                //elem["title"]=(int)x.doc_id;
               // elem["weight"]=x.weight;
                elem["title"]=doc->title;
                elem["desc"]=Getdesc(doc->content,x.words[0]);//content是文档的去标签的结果，但是不是我们想要的，我们只要一部分
                elem["url"]=doc->url;
                root.append(elem);
            }

            Json::StyledWriter writer;
            //Json::FastWriter writer;
            *json_string =writer.write(root);

            
        }

    std::string Getdesc(const std::string html_content,const std::string word)
    {
        //找到word在htmlcontent中首次出现，然后往前找50字节（如果没有，从begin开始），往后找100字节（如果没有，到end就可以）
        const std::size_t prev_step=50;
        const std::size_t next_step=100;
        
        //获取start，end 
        size_t start=0;
        size_t end=html_content.size()-1;
        
        //首次出现的位置
        auto iter=std::search(html_content.begin(),html_content.end(),word.begin(),word.end(),[](int x,int y){
                return (std::tolower(x)==tolower(y));
                });

        
        
        if(iter==html_content.end())//这种情况不可能出现
        {
            return "None1";
        }

        const size_t pos=std::distance(html_content.begin(),iter);
        
        //有前50+字节，就开始更新位置
        if(pos>start+prev_step)//这里运算的时候要注意size_t是无符号整形
        {
            start=pos-prev_step;
        }
        //有后100字节，就开始更新位置
        if(pos<(int)(end-next_step))   //这里运算的时候要注意size_t是无符号整形
        {
            end=pos+next_step;
        }
        
        
        //3.截取子串
       if(start>end)
       {
           return "None2";
       }

       std::string desc=html_content.substr(start,end-start);
       return desc;
    }


    private:
        ns_index::Index* index;
    };
}
